<template>
	<div class="base__scroll__list" :id="baseScrollListId">
		<div
			class="base__scroll__list__header"
			:style="{
				backgroundColor: realConfig.headerBackground,
				height: `${(realConfig.headerHeight / 1920) * 100}vw`,
				fontSize: `${(realConfig.headerFontSize / 1920) * 100}vw`,
				color: realConfig.headerColor,
			}"
		>
			<div
				class="header__item base__scroll__list__text"
				v-for="(headerItem, headerItemIndex) in headerData"
				:key="`${headerItem}/${headerItemIndex}`"
				:style="{
					width: `${columnWidths[headerItemIndex]}px`,
					...headerStyleData[headerItemIndex],
				}"
				v-html="headerItem"
				:align="aligns[headerItemIndex]"
			/>
		</div>
		<div class="base__scroll__list__rows__wrapper" :style="{ height: `${height - realConfig.headerHeight - 16}px` }">
			<div
				class="base__scroll__list__rows"
				v-for="(rowsItem, index) in currRowsData"
				:key="`${rowsItem.rowIndex}/${index}`"
				:style="{
					height: `${(rowHeights[index] / 1920) * 100}vw`,
					lineHeight: `${(rowHeights[index] / 1920) * 100}vw`,
					backgroundColor: rowBackground[rowsItem.rowIndex % 2],
					fontSize: `${(realConfig.rowFontSize / 1920) * 100}vw`,
					color: realConfig.rowColor,
				}"
			>
				<div
					class="base__scroll__list__column base__scroll__list__text"
					v-for="(colomnItem, colIndex) in rowsItem.data"
					:key="`${colomnItem}/${colIndex}`"
					:style="{
						width: `${columnWidths[colIndex]}px`,
						...headerStyleData[colIndex],
						...rowStyle[colIndex],
					}"
					:align="aligns[colIndex]"
					v-html="colomnItem"
				/>
			</div>
		</div>
	</div>
</template>

<script setup>
import { v4 as uuidv4 } from 'uuid';

const clone = (origin) => {
	return JSON.parse(JSON.stringify(origin));
};

const defaultConfig = {
	// 标题数据 ['a', 'b', 'c']
	header: [],
	// 标题样式 [{}, {}, {}]
	headerStyle: [],
	// 行样式
	rowStyle: [],
	// 标题背景色
	headerBackground: 'rgba(90, 90, 90, .8)',
	// 行背景色
	rowBackground: [],
	// header默认高度
	headerHeight: 40,
	// 是否展示序号
	showHeaderIndex: false,
	// 序号列标题内容
	headerIndexText: '#',
	// 序号列每行显示的内容
	headerIndexData: [],
	// header序号样式
	headerIndexStyle: {
		width: '50px',
	},
	// row序号样式
	rowIndexStyle: {
		width: '50px',
	},
	// 表格数据
	rowsData: [],
	// 默认展示5行
	rowNum: 5,
	// 对齐方式
	aligns: [],
	// header字体默认大小
	headerFontSize: 28,
	// 行数据字体默认大小
	rowFontSize: 24,
	// header字体默认颜色
	headerColor: '#fff',
	// row字体默认颜色
	rowColor: '#fff',
	// 每次向上滚动的row数量
	perMoveNum: 1,
	// 每次默认延迟2s滚动
	duration: 2000,
};

defineOptions({
	name: 'baseScrollList',
});

const props = defineProps({
	config: {
		type: Object,
		default: () => {},
	},
});

watch(
	() => props.config,
	async () => {
		await nextTick();
		updateBaseScrollListStyle();
		update();
	}
);

const baseScrollListId = `baseScrollList-${uuidv4()}`;
const width = ref(0);
const height = ref(0);
const headerData = ref([]);
const headerStyleData = ref([]);
const realConfig = ref({});
const columnWidths = ref([]);
const rowsData = ref([]);
const currRowsData = ref([]);
const currIndex = ref(0);
const rowHeights = ref([]);
const rowNum = ref(defaultConfig.rowNum);
const rowStyle = ref([]);
const rowBackground = ref([]);
const aligns = ref([]);
const isAnimationStart = ref(true);

const transitionTime = 300;

let averageHeight;

// 处理header
const handleHeader = (config) => {
	if (!config || !config.header.length) {
		return;
	}
	const _header = [...config.header];
	const _headerStyle = clone(config.headerStyle);
	const _rowsData = clone(config.rowsData);
	const _rowStyle = clone(config.rowStyle);
	const _aligns = clone(config.aligns);
	// 显示序列号
	if (config.showHeaderIndex) {
		_header.unshift(config.headerIndexText);
		_headerStyle.unshift(config.headerIndexStyle);
		_rowStyle.unshift(config.rowIndexStyle);
		_rowsData.forEach((row, rowIndex) => {
			if (config.headerIndexData && config.headerIndexData.length && config.headerIndexData[rowIndex]) {
				row.unshift(config.headerIndexData[rowIndex]);
			} else {
				row.unshift(++rowIndex);
			}
		});
		// 序列号默认居中对齐
		_aligns.unshift('center');
	}

	headerData.value = _header;
	headerStyleData.value = _headerStyle;

	const { rowNum } = config;
	// 当列表数据项长度 和 需要展示的列长度相同时，默认渲染两倍数据项（否则最后一列视觉上有误）
	if (_rowsData.length === rowNum) {
		const doubleRowsData = [..._rowsData, ..._rowsData];
		rowsData.value = doubleRowsData.map((item, index) => {
			return {
				data: item,
				rowIndex: index,
			};
		});
	} else {
		rowsData.value = _rowsData.map((item, index) => {
			return {
				data: item,
				rowIndex: index,
			};
		});
	}

	rowStyle.value = _rowStyle;
	aligns.value = _aligns;

	// 动态计算header每一列的宽度
	const headerLength = _header.length;

	let usedWidth = 0;
	let usedColumn = 0;
	// 支持自定义宽度
	_headerStyle.forEach((item) => {
		if (item.width) {
			usedWidth += +item.width.replace('px', '');
			usedColumn++;
		}
	});

	const averageWidth = Math.floor((width.value - usedWidth) / (headerLength - usedColumn));
	const _columnWidths = new Array(headerLength).fill(averageWidth);
	columnWidths.value = _columnWidths;
};

// 处理行数据
const handleRows = (config) => {
	// 动态计算每行数据的高度
	const { headerHeight } = config;
	const unusedHeight = height.value - headerHeight - 16;

	// 如果rowNum大于实际数据
	const rowsDataLength = rowsData.value.length;
	rowNum.value = config.rowNum;

	if (rowNum.value > rowsDataLength) {
		rowNum.value = rowsDataLength;
	}

	averageHeight = unusedHeight / rowNum.value;
	const _rowHeights = new Array(rowNum.value).fill(averageHeight);
	rowHeights.value = _rowHeights;

	// 获取行背景色
	if (config.rowBackground) {
		rowBackground.value = config.rowBackground;
	}

	// 默认赋值一次 （否则当rowData数据量 < rowNum时， 列表不显示）
	currRowsData.value = rowsData.value;
};

// 开启动画
const startAnimation = async () => {
	if (!isAnimationStart.value) return;
	const config = realConfig.value;
	const { rowNum, perMoveNum, duration } = config;
	if (rowsData.value.length < rowNum) {
		return;
	}
	// 首尾相接
	let index = currIndex.value;
	const _rowsData = clone(rowsData.value);
	const _currRowsData = _rowsData.slice(index, index + rowNum + 1);
	// perMoveNum 暂定为 1
	if (index + rowNum >= rowsData.value.length - 1) {
		_currRowsData.push(..._rowsData.slice(0, rowNum + 2 - _currRowsData.length));
	} else {
		_currRowsData.push(..._rowsData.slice(index + rowNum + 1, index + 1 + rowNum + perMoveNum));
	}

	currRowsData.value = _currRowsData;

	// 动画逻辑 1. 所有高度还原 2.将rowNum之前所有列高度设为0
	rowHeights.value = new Array(rowsData.value.length).fill(averageHeight);
	if (!isAnimationStart.value) return;
	await new Promise((resolve) => setTimeout(resolve, transitionTime));
	rowHeights.value.splice(0, perMoveNum, ...new Array(perMoveNum).fill(0));

	// 更新currIndex
	currIndex.value += perMoveNum;
	currIndex.value %= rowsData.value.length;

	if (!isAnimationStart.value) return;
	await new Promise((resolve) => setTimeout(resolve, duration - transitionTime));
	if (!isAnimationStart.value) return;
	await startAnimation();
};

const stopAnimation = () => {
	isAnimationStart.value = false;
};

// 合并配置
const mergeConfig = () => {
	return Object.assign(defaultConfig, props.config);
};

const update = () => {
	// 先停止动画
	stopAnimation();

	const _realConfig = mergeConfig();
	rowsData.value = _realConfig.rowsData;
	handleHeader(_realConfig);
	handleRows(_realConfig);
	realConfig.value = _realConfig;

	isAnimationStart.value = true;
	// 开启动画
	startAnimation();
};

const updateBaseScrollListStyle = () => {
	const dom = document.querySelector(`#${baseScrollListId}`);
	width.value = dom.clientWidth;
	height.value = dom.clientHeight;
};
</script>

<style lang="scss" scoped>
.base__scroll__list {
	width: 100%;
	height: 100%;
	.base__scroll__list__text {
		display: -webkit-box;
		-webkit-box-orient: vertical;
		-webkit-line-clamp: 1;
		overflow: hidden;
		box-sizing: border-box;
	}
	.base__scroll__list__header {
		display: flex;
		align-items: center;
		font-size: 30px;
		overflow: hidden;
		margin-bottom: 6px;
	}
	.base__scroll__list__rows__wrapper {
		overflow: hidden;
		.base__scroll__list__rows {
			display: flex;
			transition: all 0.3s linear;
		}
	}
}
</style>
